package com.hps.shiro.controller;

import com.hps.shiro.model.User;
import com.hps.shiro.service.AuthorizeService;
import lombok.AllArgsConstructor;
import org.apache.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.error.OAuthError;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.OAuthResponse;
import org.apache.oltu.oauth2.common.message.types.ParameterStyle;
import org.apache.oltu.oauth2.common.utils.OAuthUtils;
import org.apache.oltu.oauth2.rs.request.OAuthAccessResourceRequest;
import org.apache.oltu.oauth2.rs.response.OAuthRSResponse;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 1、首先通过如http://localhost:9090/oauth-server/userInfo?access_token=828beda907066d058584f37bcfd597b6进行访问；
 * 2、该控制器会验证access token的有效性；如果无效了将返回相应的错误，客户端再重新进行授权；
 * 3、如果有效，则返回当前登录用户的用户名。
 * @author heps
 * @since 2020/6/8 13:52
 */
@AllArgsConstructor
@Controller
@RequestMapping("/oauth-server")
public class UserInfoController {

  private final AuthorizeService authorizeService;

  @RequestMapping("/userInfo")
  public HttpEntity userInfo(HttpServletRequest request) throws OAuthSystemException {
    try {

      //构建OAuth资源请求
      OAuthAccessResourceRequest oauthRequest = new OAuthAccessResourceRequest(request, ParameterStyle.QUERY);
      //获取Access Token
      String accessToken = oauthRequest.getAccessToken();

      //验证Access Token
      if (!authorizeService.checkAccessToken(accessToken)) {
        // 如果不存在/过期了，返回未验证错误，需重新验证
        OAuthResponse oauthResponse = OAuthRSResponse
            .errorResponse(HttpServletResponse.SC_UNAUTHORIZED)
            .setRealm("oauth-server")
            .setError(OAuthError.ResourceResponse.INVALID_TOKEN)
            .buildHeaderMessage();

        HttpHeaders headers = new HttpHeaders();
        headers.add(OAuth.HeaderType.WWW_AUTHENTICATE, oauthResponse.getHeader(OAuth.HeaderType.WWW_AUTHENTICATE));
        return new ResponseEntity(headers, HttpStatus.UNAUTHORIZED);
      }
      //返回用户名
      User user = authorizeService.getUserByAccessToken(accessToken);
      return new ResponseEntity(user, HttpStatus.OK);
    } catch (OAuthProblemException e) {
      //检查是否设置了错误码
      String errorCode = e.getError();
      if (OAuthUtils.isEmpty(errorCode)) {
        OAuthResponse oauthResponse = OAuthRSResponse
            .errorResponse(HttpServletResponse.SC_UNAUTHORIZED)
            .setRealm("fxb")
            .buildHeaderMessage();

        HttpHeaders headers = new HttpHeaders();
        headers.add(OAuth.HeaderType.WWW_AUTHENTICATE, oauthResponse.getHeader(OAuth.HeaderType.WWW_AUTHENTICATE));
        return new ResponseEntity(headers, HttpStatus.UNAUTHORIZED);
      }

      OAuthResponse oauthResponse = OAuthRSResponse
          .errorResponse(HttpServletResponse.SC_UNAUTHORIZED)
          .setRealm("oauth-server")
          .setError(e.getError())
          .setErrorDescription(e.getDescription())
          .setErrorUri(e.getUri())
          .buildHeaderMessage();

      HttpHeaders headers = new HttpHeaders();
      headers.add(OAuth.HeaderType.WWW_AUTHENTICATE, oauthResponse.getHeader(OAuth.HeaderType.WWW_AUTHENTICATE));
      return new ResponseEntity(HttpStatus.BAD_REQUEST);
    }
  }
}
